import type { Ref } from 'vue'
import { ref, watch, computed, onMounted, onUnmounted, nextTick } from 'vue'
import DynamicComp from 'generator/index/Layout/WorkBench/Dynamic/index.vue'
import { getUuid } from 'wft-utils';
import Bus from '@/utils/bus';
import { BaseEventEnum, DragEventEnum, DragKeyEnum, KeyEventEnum } from '@/enums'
import { useMessage } from '@/hooks';

type AnyFunc = (...args: any[]) => void;
export function usePanel(
  panelJson: Ref<TPanel>,
  emits: AnyFunc,
  savePanelJson: AnyFunc,
  undo: AnyFunc,
  redo: AnyFunc,
  toggleLayer: AnyFunc,
  deleteComp: AnyFunc,
  toggleInertia: AnyFunc,
  openInertia: AnyFunc
) {

  const dynamicDraggableListRef = ref<Array<InstanceType<typeof DynamicComp>>>([])

  const vLine = ref<any[]>([])
  const hLine = ref<any[]>([])

  onMounted(() => {
    startEvent()
    document.addEventListener(BaseEventEnum.ON_MOUSE_DOWN, docMousedown)
    Bus.on('startEventKeydown', startEventKeydown)
  })

  onUnmounted(() => {
    clearEvent()
    Bus.off('startEventKeydown', startEventKeydown)
  })

  const renderComps = computed(() => panelJson.value.children.filter(item => item.config.visible && item.type != 'inertia'))

  const inertiaComps = computed(() => panelJson.value.children.filter(item => item.type == 'inertia'))

  const advancedEnchaseCollect = computed(() => panelJson.value.children.filter(item => item.type == 'advanced').map(item => item.config.isEnchase!) || [])
  const navigationConfig = computed(() => {
    if (panelJson.value.isGlobal) {
      return (panelJson.value.children[0] as unknown as TGlobalComp)?.attrs?.globalStyle || {}
    }
    return {}
  })

  watch(() => advancedEnchaseCollect, () => {
    if (advancedEnchaseCollect.value.some(bool => bool)) {
      clearEvent()
    } else {
      startEvent()
    }
  }, { deep: true })

  watch(() => panelJson.value.style.height, () => {
    nextTick(() => {
      initParentPanelSize()
    })
  }, { deep: true })

  // 鼠标按下中间开始监听键盘事件
  function docMousedown(event: MouseEvent) {
    const wftWorkBenchContainerEl = document.getElementById('wft-work-bench-container')
    if(!wftWorkBenchContainerEl) return
    if (wftWorkBenchContainerEl!.contains(<Node>event.target)) {
      startEventKeydown()
    } else {
      document.removeEventListener(KeyEventEnum.ON_KEY_DOWN, onKeydown)
    }
  }

  // 监听键盘事件 无论之前有无监听过 先移除一次
  function startEventKeydown() {
    document.removeEventListener(KeyEventEnum.ON_KEY_DOWN, onKeydown)
    document.addEventListener(KeyEventEnum.ON_KEY_DOWN, onKeydown)
  }

  // 键盘事件  Ctrl + S  保存入库
  function onKeydown (event: KeyboardEvent) {
    event.preventDefault()
    const { altKey, ctrlKey, key } = event
    if (ctrlKey && key == 's') {
      savePanelJson(panelJson.value)
    }
    if(key == 'z' && ctrlKey) {
      undo()
    }
    if(key == 'y' && ctrlKey) {
      redo()
    }
    if(key == 'l' && ctrlKey && !altKey) {
      toggleLayer()
    }
    if(key == 'k' && ctrlKey && !altKey) {
      toggleInertia()
    }
    if(key == 'Delete') {
      deleteComp()
    }
  }

  // 监听事件
  function startEvent () {
    const mobileContainerPanel = document.getElementById('wft-mobile-container-panel')!
    mobileContainerPanel.addEventListener(DragEventEnum.ON_DRAG_OVER, compDragover)
    mobileContainerPanel.addEventListener(DragEventEnum.ON_DROP, compDrop)
  }
  
  // 清除事件
  function clearEvent () {
    const mobileContainerPanel = document.getElementById('wft-mobile-container-panel')
    if (mobileContainerPanel) {
      mobileContainerPanel.removeEventListener('dragover', compDragover)
      mobileContainerPanel.removeEventListener('drop', compDrop)
    }
  }

  // 组件激活
  function compActive (curComp: TComp) {
    if (curComp.parentId) {
      // 保证只有一个激活
      const parent = panelJson.value.children.find(comp => comp.id == curComp.parentId)
      if (parent) parent.config.isActive = false
    }
    emits('onActivated', curComp)
  }

  // 初始化父元素大小
  function initParentPanelSize () {
    if(dynamicDraggableListRef.value && dynamicDraggableListRef.value.length) {
      dynamicDraggableListRef.value.forEach(dynamicdr => {
        dynamicdr.checkParentSize()
      })
    }
  }

  function compDragover (e: DragEvent) {
    e.preventDefault()
  }

  // 松开拖拽组件
  function compDrop (event: DragEvent) {
    if (!event.dataTransfer?.getData(DragKeyEnum.DRAG_DATA_KEY)) return
    const dragData = JSON.parse(event.dataTransfer.getData(DragKeyEnum.DRAG_DATA_KEY))
    if(dragData.curCom.key == 'form') {
      if(panelJson.value.children.findIndex(item => item.key == 'form') >= 0) {
        return useMessage().warning('页面中只能存在一个表单容器！')
      }
    }
    const curCom = JSON.parse(JSON.stringify(dragData.curCom))
    curCom.id = getUuid()
    curCom.parentId = null
    curCom.parentKey = null
    if(curCom.type != 'inertia') { // 非惰性控件
      const mobileContainerPanel = document.querySelector('#wft-mobile-container-panel')!
      const { left, top, width, height } = mobileContainerPanel.getBoundingClientRect()
      curCom.style.grid.top = Math.floor(event.clientY - top - dragData.offsetY)
      curCom.style.grid.left = curCom.style.percent.width == '100%' ? 0 : Math.floor(event.clientX - left - dragData.offsetX)
      curCom.style.percent.top = ((curCom.style.grid.top / height) * 100).toFixed(0) + '%'
      curCom.style.percent.left = ((curCom.style.grid.left / width) * 100).toFixed(0) + '%'
      curCom.style.percent.height = ((curCom.style.grid.height / height) * 100).toFixed(0) + '%'
      if (curCom.style.percent.width == '100%') {
        curCom.style.grid.width = parseInt(String(width))
      } else {
        curCom.style.percent.width = ((curCom.style.grid.width / width) * 100).toFixed(0) + '%'
      }
    } else { // 惰性控件
      openInertia()
    }
    curCom.config.isActive = true
    panelJson.value.children?.forEach(item => item.config.isActive = false)
    emits('onActivated', curCom)
    panelJson.value.children?.push(curCom)
    Bus.emit('addStack')
    startEventKeydown()
    if (event.dataTransfer?.getData(DragKeyEnum.DRAG_DATA_KEY)) {
      event.dataTransfer.clearData(DragKeyEnum.DRAG_DATA_KEY)
    }
  }

  // 辅助线回调事件
  function getRefLineParams (params: any) {
    const { vLine: VL, hLine: HL } = params
    let id = 0
    vLine.value = VL.map((item: any) => {
      item['id'] = ++id
      return item
    })
    hLine.value = HL.map((item: any) => {
      item['id'] = ++id
      return item
    })
  }

  return {
    renderComps,
    inertiaComps,
    dynamicDraggableListRef,
    vLine,
    hLine,
    navigationConfig,
    compActive,
    getRefLineParams
  }
}